//go:build linux
// +build linux

package main

import (
	"fmt"
	"net"
	"os"
	"syscall"
)

func main() {
	if len(os.Args) != 3 {
		fmt.Fprintf(os.Stderr, "usage: go run sendfile_server_linux.go <listenAddr> <file>\n")
		os.Exit(1)
	}
	addr := os.Args[1] // 例如 ":5678"
	filePath := os.Args[2]

	listener, err := net.Listen("tcp", addr)
	if err != nil {
		panic(err)
	}
	defer listener.Close()
	fmt.Printf("[server] listening on %s, serving %s\n", addr, filePath)

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("[server] accept error: %v\n", err)
			continue
		}
		go handle(conn.(*net.TCPConn), filePath)
	}
}

func handle(conn *net.TCPConn, filePath string) {
	defer conn.Close()

	f, err := os.Open(filePath)
	if err != nil {
		fmt.Printf("[server] open file error: %v\n", err)
		return
	}
	defer f.Close()

	stat, err := f.Stat()
	if err != nil {
		fmt.Printf("[server] stat file error: %v\n", err)
		return
	}
	remaining := stat.Size()

	outFile, err := conn.File() // 复制一个底层 fd，便于传给 sendfile
	if err != nil {
		fmt.Printf("[server] get conn fd error: %v\n", err)
		return
	}
	defer outFile.Close()

	outFD := int(outFile.Fd())
	inFD := int(f.Fd())

	for remaining > 0 {
		chunk := remaining
		if chunk > 1<<30 { // sendfile 的 count 参数是 int，切分巨型文件
			chunk = 1 << 30
		}
		n, err := syscall.Sendfile(outFD, inFD, nil, int(chunk))
		if err != nil {
			fmt.Printf("[server] sendfile error: %v\n", err)
			return
		}
		remaining -= int64(n)
	}
	fmt.Printf("[server] transfer complete, bytes=%d\n", stat.Size())
}
